package com.aloha.springframework.beans.factory.support;

import com.aloha.springframework.beans.BeansException;
import com.aloha.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.aloha.springframework.beans.factory.config.BeanDefinition;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author DaiZhiHeng
 * @description 容器的一个默认实现类
 * @date 2023/7/1 23:05
 */
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ConfigurableListableBeanFactory {

    // 存放bean定义信息的容器
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) {
            throw new BeansException("未在容器中定义名为 [" + beanName + "] 的bean");
        }
        return beanDefinition;
    }

    @Override
    public void preInstantiateSingletons() throws BeansException {
        // 预先实例化所有单例Bean并且非懒加载的Bean
        beanDefinitionMap.entrySet().stream().filter(entry -> entry.getValue().isSingleton() && !entry.getValue().isLazyInit()).forEach(entry -> getBean(entry.getKey()));
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return beanDefinitionMap.entrySet().stream().filter(e -> type.isAssignableFrom(e.getValue().getBeanClass())).collect(Collectors.toMap(Map.Entry::getKey, e -> getBean(e.getKey(), type)));
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
        return beanDefinitionMap.containsKey(beanName);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return beanDefinitionMap.keySet().toArray(new String[0]);
    }


    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        List<String> beanNames = beanDefinitionMap.entrySet().stream().filter(entry -> requiredType.isAssignableFrom(entry.getValue().getBeanClass())).map(Map.Entry::getKey).collect(Collectors.toList());
        if (beanNames.size() == 1) return getBean(beanNames.get(0), requiredType);
        throw new BeansException(requiredType + " 类型的对象有: " + beanNames.size() + "个 " + beanNames);
    }
}
